package algorithm1_v3;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Initialization {
	static Logger logger= LoggerFactory.getLogger(Initialization.class);
	private static HashMap<String,String> paramControl(String[] args){
		HashMap<String,String> params=new HashMap<String,String>();
		params.put("timeUnit","500");
		params.put("processes","processes");
		params.put("leader","leader");
		params.put("incarnation","incarnation");
		
		for (int i=0;i<args.length;i++){
			switch (args[i]){
			case "-h":
			case "--help":
				System.out.println("-h,--help/n/t laguntza/n" +
						"-u,--unit/n/t erabiliko den denbora lapsoa milisegundutan (lehenetsia 500ms)/n" +
						"-p,--processes/n/t parte hartuko duten prozesuen fitxategiaren path-a/n (lehenetsia ./processes)" +
						"Honako hauek sistema testeatzeko parametroak dira, ez erabili sistemaren prozesamentu normal bat nahi bada"+
						"-l,--leader/n/t liderra gordeko duen fitxategiaren path-a/n (lehenetsia ./leader)" +
						"-i,--incarnation/n/t incarnation gordeko duen fitxaegiaren path-a/n (lehenetsia ./incarnation)");
				break;
			case "-u":
			case "--unit":
				String timeUnit=args[i+1];
				params.put("timeUnit",timeUnit);
				break;
			case "-p":
			case "--processes":
				String fileProcesses=args[i+1];
				params.put("processes",fileProcesses);
				break;
			case "-l":
			case "--leader":
				String fileLeader=args[i+1];
				params.put("leader",fileLeader);
				break;
			case "-i":
			case "--incarnation":
				String fileIncarnation=args[i+1];
				params.put("incarnation",fileIncarnation);
				break;
			}
		}
		return params;
	}
	public static ArrayList<String> getProcesses(String fileProcesses) {
		ArrayList<String> processes = new ArrayList<String>();
		try {
			BufferedReader processFile = new BufferedReader(new FileReader(
					fileProcesses));
			String line = processFile.readLine();
			while (line != null) {
				processes.add(line);
				line = processFile.readLine();
			}
			processFile.close();
		} catch (Exception e) {
			logger.info("ERROREA:prozesu fitxategia irakurtzean");
			e.printStackTrace();
			System.exit(1);
		}

		return processes;
	}
	private static int readIncarnation(String fileIncarnation){
		String incNum=null;
		BufferedReader incarnationString;
		try{
		new File(fileIncarnation).createNewFile();
		incarnationString = new BufferedReader(
				new FileReader(fileIncarnation));
		incNum = incarnationString.readLine();
		incarnationString.close();
		}catch (Exception e) {
			logger.info("ERROREA:incarnation fitxategia irakurtzean");
			e.printStackTrace();
		}
		if (incNum==null)// fitxategi hutsa
			return 0;
		return Integer.parseInt(incNum);
	}
	private static void writeIncarnation(String fileIncarnation){
		SystemInfo info = SystemInfo.INSTANCE;
		FileWriter writeIncarnation;
		try {
			writeIncarnation = new FileWriter("incarnation");
			writeIncarnation.write(Integer.toString(info.incarnation[0]));
			writeIncarnation.close();
		} catch (IOException e) {
			logger.info("ERROREA:incarnation fitxategia idaztean");
			e.printStackTrace();
		}
	}
	
	private static String readLeader(String leaderFile) {
		BufferedReader fileLeader;
		String leader=null;
		try {
			new File(leaderFile).createNewFile();
			fileLeader = new BufferedReader(new FileReader(leaderFile));
			leader=fileLeader.readLine();

			fileLeader.close();
		} catch (Exception e) {
			logger.info("ERROREA:leader fitxategia irakurtzean");
			e.printStackTrace();
		}
		return leader;
	}
	private static void writeLeader(String fileIncarnation) {
		SystemInfo info = SystemInfo.INSTANCE;
		FileWriter fileLeader;
		try {
			fileLeader = new FileWriter(fileIncarnation);
			fileLeader.write(info.leader.toString());
			fileLeader.close();
		} catch (Exception e) {
			logger.info("ERROREA: leader fitxategia idaztean");
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		SystemInfo info = SystemInfo.INSTANCE;
		int incNum;
		String machineName=null;
		ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
		HashMap<String,String> params=paramControl(args);
		info.timeUnit[0]=Integer.parseInt(params.get("timeUnit"));
		//String processName = ManagementFactory.getRuntimeMXBean().getName(); -> makina izena eta prozesu zenbakia, baiño inetaddress ibilita dns-ko izena(nahiz da eztaukeun prozesu izenik)
		try {
			machineName = InetAddress.getLocalHost().getHostName();
		} catch (UnknownHostException e) {
			logger.info("ERROREA:makinaizena irakurtzean");
		}
		//baldintzako irakurketak aldagaietan gorde ezkero gero irakurketak ez dago berriz egin beharrik
		if (readIncarnation(params.get("incarnation"))==0 && readLeader(params.get("leader"))==null){
			//hilera redundantea
			info.incarnation[0]=0;
			info.leader.replace(0, info.leader.length(),machineName);
			//hilera redundantea
			writeIncarnation(params.get("incarnation"));
			writeLeader(params.get("leader"));

		}
		incNum = readIncarnation(params.get("incarnation"));
		info.incarnation[0] = ++incNum;
		writeIncarnation(params.get("incarnation"));
		info.leader.replace(0, info.leader.length(),readLeader(params.get("leader")));
		for (String q : getProcesses(params.get("processes"))) {
			if (!q.equals(machineName)) {
				info.timeout.put(q, info.timeUnit[0]+info.incarnation[0]);//info.timeUnit+info.incarnation[0]??
				info.recovered.put(q, 0);
			} else {
				info.recovered.put(q, info.incarnation[0]);
			}
		}
//		Hau task2ra pasatu da efizientzia eta kodea errazteagatik
//		if (!info.leader.equals(processName)) {
//			timerra reseteatu
//			
//		}
//		PROAU Task2yei campo bat geitzen threat bat izengo huke (ScheduledExecutorService) 
		//ta gero threat hontan lantzau task3ek. Hemen (Initializationen) sortzean ScheduledFuture-re berkoniki
		//task2yen hemen sortu dana kantzelau ahal izeteko... Nik uste oain daon bezela sinplena
		scheduler.submit(new Task2());
		scheduler.schedule(new Task1(), info.timeUnit[0]+info.incarnation[0], TimeUnit.MILLISECONDS);//info.timeUnit+info.incarnation[0]??
		
	}
}
